﻿//  此文件中定义 6502CPU各种寄存器的数据类型
namespace DA6502.CPU
{
    using addr = System.UInt16;



    /// <summary>
    /// 6502CPU状态寄存器P的各标志枚举
    /// </summary>
    public enum FLAGS
    {
        /// <summary>
        /// Carry Flag(C)，进位标志。(一般对于无符号数来说)如果最近一条指令有溢出——上溢：超出了 255，下溢：低于 0，则设置该 bit 为 1
        /// </summary>
        C,

        /// <summary>
        /// Zero Flag(Z)，零标志。最近一条指令的结果是否为0，如果是，则置1，否则置0
        /// </summary>
        Z,

        /// <summary>
        /// Interrupt Disable(I)，中断忽略标志。置1会使得系统忽略IRQ中断，清零则响应，SEI(Set Interrupt Disable) 指令将该位置 1，CLI(Clear Interrupt Disable)将该位清 0
        /// </summary>
        I,

        /// <summary>
        /// Decimal Mode(D)，BCD标志。该位用来将 6502 切换到 BCD 模式，但 NES 里面不用
        /// </summary>
        D,

        /// <summary>
        /// Break Command(B)，BRK命令标志。该位用来表示一个 BRK(Break) 指令在执行，该指令就是发出一个 IRQ 中断，类似 x86 下的 INT
        /// </summary>
        B,

        /// <summary>
        /// Unused(U)，未使用标志。虽然未使用，但实际上在JSR或者中断等跳转时此标志位会被用来与B一起表示跳转的原因
        /// </summary>
        U,

        /// <summary>
        /// Overflow Flag(V)，溢出标志。(一般对于有符号数来说)，如果运算有溢出，则置 1
        /// </summary>
        V,

        /// <summary>
        /// Negative Flag(N)，负标志。该位就是运算结果的最高位
        /// </summary>
        N
    }

    /// <summary>
    /// 6502CPU中的单字节寄存器名称
    /// </summary>
    public enum REGISTER_BYTE
    {
        /// <summary>
        /// Accumulator(A)，累加器A。用来存放运算结果或者从内存取回来的数据
        /// </summary>
        A,

        /// <summary>
        /// Index Register X(X)，变址寄存器X。用来作为循环的计数器或者特定寻址下的偏移量，也可以存放从内存取出来的数据，还能用来设置或者获取栈指针
        /// </summary>
        X,

        /// <summary>
        /// Index Register Y(Y)，变址寄存器Y。 用来作为循环的计数器或者特定寻址下的偏移量，也可以存放从内存取出来的数据，但是不能用来设置栈指针
        /// </summary>
        Y,

        /// <summary>
        /// Processor Status(P)，状态寄存器。保存了FLAGS中的各个标志位：
        /// </summary>
        P,

        /// <summary>
        /// Stack Pointer(S/SP)，栈指针。6502 架构下的栈也是上下颠倒向下扩展的，即 push 一个元素 SP 减小，POP 一个元素 SP 增加。
        /// </summary>
        S
    }

    /// <summary>
    /// 6502CPU中的双字节寄存器名称
    /// </summary>
    public enum REGISTER_WORD
    {

        /// <summary>
        /// Program Counter (PC)，程序计数器。存放下一条指令的地址，一条指令执行时就会更新这个寄存器的值，使它指向下一条指令的地址。
        /// </summary>
        PC
    }

    /// <summary>
    /// CPU寄存器结构体
    /// </summary>
    public struct Registers
    {
        public addr PC;
        public byte S;
        public byte P;
        public byte A;
        public byte X;
        public byte Y;

        public Registers(ushort pC, byte s, byte p, byte a, byte x, byte y)
        {
            PC = pC;
            S = s;
            P = p;
            A = a;
            X = x;
            Y = y;
        }

        public Registers(CPU cpu)
        {
            PC = cpu.GetRegisterWord(REGISTER_WORD.PC);
            S = cpu.GetRegisterByte(REGISTER_BYTE.S);
            P = cpu.GetRegisterByte(REGISTER_BYTE.P);
            A = cpu.GetRegisterByte(REGISTER_BYTE.A);
            X = cpu.GetRegisterByte(REGISTER_BYTE.X);
            Y = cpu.GetRegisterByte(REGISTER_BYTE.Y);
        }

        /// <summary>
        /// 从CPU中取寄存器状态
        /// </summary>
        /// <param name="cpu"></param>
        public void ExtractRegisters(CPU cpu)
        {
            PC = cpu.GetRegisterWord(REGISTER_WORD.PC);
            S = cpu.GetRegisterByte(REGISTER_BYTE.S);
            P = cpu.GetRegisterByte(REGISTER_BYTE.P);
            A = cpu.GetRegisterByte(REGISTER_BYTE.A);
            X = cpu.GetRegisterByte(REGISTER_BYTE.X);
            Y = cpu.GetRegisterByte(REGISTER_BYTE.Y);
        }

        /// <summary>
        /// 将寄存器状态反映到CPU中
        /// </summary>
        /// <param name="cpu"></param>
        public void ReleaseRegisters(CPU cpu)
        {
            cpu.SetRegisterWord(REGISTER_WORD.PC, PC);
            cpu.SetRegisterByte(REGISTER_BYTE.S, S);
            cpu.SetRegisterByte(REGISTER_BYTE.P, P);
            cpu.SetRegisterByte(REGISTER_BYTE.A, A);
            cpu.SetRegisterByte(REGISTER_BYTE.X, X);
            cpu.SetRegisterByte(REGISTER_BYTE.Y, Y);
        }

        public string DumpRegisters()
        {
            string msg = "";
            msg += "PC:" + PC.ToString("X4");
            msg += " A:" + A.ToString("X2");
            msg += " X:" + X.ToString("X2");
            msg += " Y:" + Y.ToString("X2");
            msg += " S:" + S.ToString("X2");
            msg += " P:" + P.ToString("X2");

            return msg;
        }
    }
}